/*
* Copyright 2013 GiavaCms.org.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.giavacms.common.repository;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.giavacms.common.annotation.LogOperation;
import org.giavacms.common.model.BaseEntity;
import org.giavacms.common.model.Group;
import org.giavacms.common.model.Search;
import org.jboss.logging.Logger;
/**
* @author fiorenzo pizza
*
* @param <T>
*/
public abstract class AbstractRepository<T> implements Serializable,
Repository<T>
{
private static final long serialVersionUID = 1L;
// --- JPA ---------------------------------
/**
* @return
*/
protected abstract EntityManager getEm();
public abstract void setEm(EntityManager em);
// --- Logger -------------------------------
protected static final Logger logger = Logger
.getLogger(AbstractRepository.class.getName());
// --- Mandatory logic --------------------------------
// protected abstract Class<T> getEntityType();
@SuppressWarnings("unchecked")
protected Class<T> getEntityType()
{
ParameterizedType parameterizedType = (ParameterizedType) getClass()
.getGenericSuperclass();
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
// --- CRUD --------------
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#create(java.lang.Class<T>)
*/
public T create(Class<T> domainClass)
{
try
{
return domainClass.newInstance();
}
catch (Exception ex)
{
logger.error(ex.getMessage(),ex);
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#persist(java.lang.Object)
*/
@LogOperation
public T persist(T object)
{
try
{
object = prePersist(object);
if (object != null)
{
getEm().persist(object);
}
return object;
}
catch (Exception e)
{
logger.error(e.getMessage(),e);
return null;
}
}
/**
* Override this if needed
*
* @param object
* @return the object to be persisted
*/
protected T prePersist(T object)
{
return object;
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#find(java.lang.Object)
*/
public T find(Object key)
{
try
{
return getEm().find(getEntityType(), key);
}
catch (Exception e)
{
logger.error(e.getMessage(),e);
return null;
}
}
public String testKey(String key)
{
String keyNotUsed = key;
boolean found = false;
int i = 0;
while (!found)
{
logger.info("key to search: " + keyNotUsed);
T obj = getEm().find(getEntityType(), keyNotUsed);
logger.info("found: " + obj);
if (obj != null)
{
i++;
keyNotUsed = key + "-" + i;
}
else
{
found = true;
return keyNotUsed;
}
}
return "";
}
/*
* (non-Javadoc)
*
* per ora definisco il metodo in modo da poterne eseguire l'invocazione..
*
* poi l'implementazione via reflections verrĂ pian piano...
*/
public T fetch(Object key)
{
try
{
return getEm().find(getEntityType(), key);
}
catch (Exception e)
{
logger.error(e.getMessage(),e);
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#update(java.lang.Object)
*/
@LogOperation
public boolean update(T object)
{
try
{
object = preUpdate(object);
getEm().merge(object);
return true;
}
catch (Exception e)
{
logger.error(e.getMessage(),e);
return false;
}
}
/**
* Override this if needed
*
* @param object
* @return
*/
protected T preUpdate(T object)
{
return object;
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#delete(java.lang.Object)
*/
@LogOperation
public boolean delete(Object key)
{
try
{
T obj = getEm().find(getEntityType(), key);
if (obj != null)
{
getEm().remove(obj);
// getEm().flush();
}
return true;
}
catch (Exception e)
{
logger.error(e.getMessage(),e);
return false;
}
}
// --- LIST ------------------------------------------
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#getAllList()
*/
@SuppressWarnings("unchecked")
public List<T> getAllList()
{
try
{
CriteriaQuery<T> criteriaQuery = (CriteriaQuery<T>) getEm()
.getCriteriaBuilder().createQuery();
criteriaQuery.select(criteriaQuery.from(getEntityType()));
return getEm().createQuery(criteriaQuery).getResultList();
}
catch (Exception ex)
{
logger.error(ex.getMessage(),ex);
return new ArrayList<T>();
}
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#getList(com.eggsweb.commons .par.Search, int, int)
*/
@SuppressWarnings("unchecked")
public List<T> getList(Search<T> search, int startRow, int pageSize)
{
try
{
List<T> result = null;
boolean count = false;
Query res = getRestrictions(search, count);
if (res == null)
return result;
if (startRow >= 0)
{
res.setFirstResult(startRow);
}
if (pageSize > 0)
{
res.setMaxResults(pageSize);
}
result = (List<T>) res.getResultList();
return result == null ? new ArrayList<T>() : result;
}
catch (Exception ex)
{
logger.error(ex.getMessage(),ex);
return new ArrayList<T>();
}
}
@SuppressWarnings("unchecked")
public List<Group<T>> getGroups(Search<T> search, int startRow, int pageSize)
{
List<Group<T>> result = new ArrayList<Group<T>>();
try
{
if (search.getGrouping() == null || search.getGrouping().trim().length() == 0
|| search.getGrouping().trim().split(",").length == 0)
{
List<T> list = getList(search, startRow, pageSize);
for (T t : list)
{
result.add(new Group<T>(1L, t));
}
return result;
}
Map<String, Object> params = new HashMap<String, Object>();
String alias = "c";
StringBuffer sb = new StringBuffer();
String groups[] = search.getGrouping().trim().split(",");
String countAlias = "counting";
sb.append("select count(").append(alias).append(".").append(groups[0]).append(") as ").append(countAlias)
.append(", ");
for (int i = 0; i < groups.length; i++)
{
sb.append(alias).append(".").append(groups[i]).append(i == groups.length - 1 ? "" : ", ");
}
sb.append(" from ").append(search.getObj().getClass().getSimpleName()).append(" ").append(alias);
String separator = " where ";
applyRestrictions(search, alias, separator, sb, params);
sb.append(" group by ");
for (int i = 0; i < groups.length; i++)
{
sb.append(alias).append(".").append(groups[i]).append(i == groups.length - 1 ? "" : ", ");
}
sb.append(" order by ").append(countAlias).append(" desc ");
Query q = getEm().createQuery(sb.toString());
for (String param : params.keySet())
{
q.setParameter(param, params.get(param));
}
if (startRow >= 0)
{
q.setFirstResult(startRow);
}
if (pageSize > 0)
{
q.setMaxResults(pageSize);
}
List<Object[]> resultList = (List<Object[]>) q.getResultList();
if (resultList == null || resultList.size() == 0)
{
return result;
}
Long max = (Long) resultList.get(0)[0];
for (Object[] resultItem : resultList)
{
T t = construct(Arrays.asList(groups), Arrays.asList(resultItem)
.subList(1, resultItem.length));
if (t != null)
{
result.add(new Group<T>((Long) resultItem[0], t, max));
}
}
return result;
}
catch (Exception ex)
{
logger.error(ex.getMessage(), ex);
return result;
}
}
/**
* Override this
*
* @param asList
* @param subList
* @return
*/
protected T construct(List<String> fieldNames, List<Object> fieldValues)
{
return null;
}
/*
* (non-Javadoc)
*
* @see com.eggsweb.commons.repository.Repository#getListSize(com.eggsweb.commons .par.Search)
*/
public int getListSize(Search<T> search)
{
Long result = new Long(0);
try
{
boolean count = true;
Query res = getRestrictions(search, count);
if ((res != null))
{
result = (Long) res.getSingleResult();
}
return result == null ? 0 : result.intValue();
}
catch (Exception e)
{
logger.info(e.getMessage());
}
return 0;
}
/**
* @param startRow
* @param pageSize
* @param res
* @return
*/
@SuppressWarnings("unchecked")
public List<T> getList(int startRow, int pageSize, Query res)
{
try
{
List<T> result = new ArrayList<T>();
result = (List<T>) res.getResultList();
if (result != null)
return result;
}
catch (Exception e)
{
logger.info(e.getMessage());
}
return new ArrayList<T>();
}
/**
* criteri di default, comuni a tutti, ma specializzabili da ogni EJB tramite overriding
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Query getRestrictions(Search<T> search, boolean justCount)
{
if (search.getObj() != null)
{
Map<String, Object> params = new HashMap<String, Object>();
String alias = "c";
StringBuffer sb = new StringBuffer(getBaseList(search.getObj()
.getClass(), alias, justCount));
String separator = " where ";
applyRestrictions(search, alias, separator, sb, params);
if (!justCount)
{
sb.append(getOrderBy(alias, search.getOrder()));
}
Query q = getEm().createQuery(sb.toString());
for (String param : params.keySet())
{
q.setParameter(param, params.get(param));
}
return q;
}
else
{
Class entityType = search.getObj().getClass();
if (entityType == null)
{
entityType = getEntityType();
}
CriteriaBuilder criteriaBuilder = getEm().getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder
.createQuery(entityType);
Root<T> rec = criteriaQuery.from(entityType);
if (justCount)
{
criteriaQuery.select((Expression) criteriaBuilder.count(rec));
}
else
{
// comanda quello della search, se non inizializzato usiamo
// quello
// di default del repository
String orderBy = search.getOrder();
if (orderBy == null)
{
orderBy = getDefaultOrderBy();
}
Path path = rec.get(orderBy);
Order order = null;
if (path != null)
{
if (search.isOrderAsc())
{
order = criteriaBuilder.asc((Expression) rec
.get(orderBy));
}
else
{
order = criteriaBuilder.desc((Expression) rec
.get(orderBy));
}
}
if (order != null)
{
criteriaQuery.orderBy(order);
}
}
return getEm().createQuery(criteriaQuery);
}
}
/**
* metodo da sovrascrivere per applicare parametri alla query, con relative condizioni d'uso
*
* esempio:
*
* String leftOuterJoinAlias = "s"; if (search.getObj().getNumero() != null &&
* search.getObj().getNumero().trim().length() > 0) { sb.append(" left outer join ").append(alias)
* .append(".serviziPrenotati ").append(leftOuterJoinAlias); // sb.append(" on "
* ).append(leftOuterJoinAlias).append(".allegati.id = ").append (alias).append(".id"); }
*
* if (search.getObj().getAttivo() != null) { sb.append(separator).append(" ").append(alias)
* .append(".attivo = :attivo "); // aggiunta alla mappa params.put("attivo", search.getObj().getAttivo()); //
* separatore separator = " and "; }
*
* if (search.getObj().getNumero() != null && !search.getObj().getNumero().trim().isEmpty()) {
* sb.append(separator).append(leftOuterJoinAlias) .append(".servizio.numero = :numero and ")
* .append(leftOuterJoinAlias) .append(".servizio.tipo = :tipoServizio "); // aggiunta alla mappa
* params.put("numero", search.getObj().getNumero()); params.put("tipoServizio", TipoServizioEnum.OMB); // separatore
* separator = " and "; }
*
* @param search
* @param alias
* @param separator
* @param sb
* @param params
*/
protected void applyRestrictions(Search<T> search, String alias,
String separator, StringBuffer sb, Map<String, Object> params)
{
}
/**
* @param criteriaBuilder
* @param current
* @param toAdd
* @return
*/
protected Predicate addAndPredicate(CriteriaBuilder criteriaBuilder,
Predicate current, Predicate toAdd)
{
return (current != null) ? criteriaBuilder.and(current, toAdd) : toAdd;
}
/**
* Serve per inizializzare un oggetto attraverso la rilettura dal db Il parametro fields contiene la lista dei nomi
* delle property su cui fare la left fetch join
*
* @param object
* @param fields
* @return
*/
@SuppressWarnings("unchecked")
public T initialize(BaseEntity object, String... fields) throws Exception
{
T p = null;
try
{
Collection<String> ff = new ArrayList<String>();
if (fields != null)
{
for (String arg : fields)
{
ff.add(arg);
}
}
if (object != null && object.getId() != null)
{
StringBuffer sb = new StringBuffer();
sb.append("FROM " + object.getClass().getSimpleName() + " rec ");
if (ff.size() > 0)
{
Field[] objectFields = object.getClass()
.getDeclaredFields();
for (Field objectField : objectFields)
{
if (ff.contains(objectField.getName()))
{
sb.append(" LEFT JOIN FETCH rec."
+ objectField.getName());
}
}
}
sb.append(" WHERE rec.id = :id");
@SuppressWarnings("rawtypes")
TypedQuery q = getEm().createQuery(sb.toString(),
object.getClass());
q.setParameter("id", object.getId());
p = (T) q.getSingleResult();
}
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
throw new Exception(e);
}
return p;
}
protected String getBaseList(Class<? extends Object> clazz, String alias,
boolean count)
{
if (count)
{
return "select count(" + alias + ") from " + clazz.getSimpleName()
+ " " + alias + " ";
}
else
{
return "select " + alias + " from " + clazz.getSimpleName() + " "
+ alias + " ";
}
}
protected abstract String getDefaultOrderBy();
public String getOrderBy(String alias, String orderBy)
{
try
{
if (orderBy == null || orderBy.length() == 0)
{
orderBy = getDefaultOrderBy();
}
StringBuffer result = new StringBuffer();
String[] orders = orderBy.split(",");
for (String order : orders)
{
result.append(", ").append(alias).append(".")
.append(order.trim()).append(" ");
}
return " order by " + result.toString().substring(2);
}
catch (Exception e)
{
return "";
}
}
protected String likeParam(String param)
{
return "%" + param + "%";
}
protected String likeParamL(String param)
{
return "%" + param;
}
protected String likeParamR(String param)
{
return param + "%";
}
}